---
title: "How we take data-driven decisions with LogSnag"
publishedAt: "2024-04-16"
summary: "It's important for every new product to take the right decisions as often you can, and thanks for our public roadmap"
image: "/images/logsnag.png"
tag: "Engineering"
---

It's important for every new product to take the right decisions as often you can, and thanks for our public roadmap, votes on feature request and building in public we have a deep connection with our users, but on top of that we also want data to back our decisions.
And thats why we have implemented LogSnag to track a lot of events so we can take data-driven decisions too.

<br />
There are planty of ways how you can implement analytics, in this blog post we will
share how we solved it in Midday using NextJS and server-actions.

<br />
Because we have a monorepo we started with creating a new package called `@midday/events`
where we install `@logsnag/next`.

<br />
The package includes all the events we want to track in Midday for example:

```typescript
{
    SignIn: {
        name: "User Signed In",
        icon: "🌝",
        channel: "login",
    },
        SignOut: {
        name: "User Signed Out",
        icon: "🌝",
        channel: "login",
    },
}
```

<br />
And based of these realtime events we can make clear graphs like Line Chart, Bar
Chart and Funnel Charts.
<br />

![LogSnag - Events](/images/graph.png)

<br />
### How we implemented LogSnag

When you sign in to Midday we first ask you about tracking, we want you to keep your privacy. This is done by showing a `Toast` component with the option to Accept or Decline, we save this decision
in a cookie so we now if we should add a identifier for the events or not.

<br />
![LogSnag - Events](/images/signin.png)
<br />

We run a server action called `tracking-consent-action.ts`:

```typescript
"use server";

import { Cookies } from "@/utils/constants";
import { addYears } from "date-fns";
import { cookies } from "next/headers";
import { action } from "./safe-action";
import { trackingConsentSchema } from "./schema";

export const trackingConsentAction = action(
  trackingConsentSchema,
  async (value) => {
    cookies().set({
      name: Cookies.TrackingConsent,
      value: value ? "1" : "0",
      expires: addYears(new Date(), 1),
    });

    return value;
  }
);
```

<br />

We then wrap the `track` method from LogSnag to enable or disabled the `user_id` to the event.

```typescript
export const setupLogSnag = async (options?: Props) => {
  const { userId, fullName } = options ?? {};
  const consent = cookies().get(Cookies.TrackingConsent)?.value === "0";

  const logsnag = new LogSnag({
    token: process.env.LOGSNAG_PRIVATE_TOKEN!,
    project: process.env.NEXT_PUBLIC_LOGSNAG_PROJECT!,
    disableTracking: Boolean(process.env.NEXT_PUBLIC_LOGSNAG_DISABLED!),
  });

  if (consent && userId && fullName) {
    await logsnag.identify({
      user_id: userId,
      properties: {
        name: fullName,
      },
    });
  }

  return {
    ...logsnag,
    track: (options: TrackOptions) =>
      logsnag.track({
        ...options,
        user_id: consent ? userId : undefined,
      }),
  };
};
```

<br />
We use the `setupLogSnag` function like this:

```typescript
export const exportTransactionsAction = action(
  exportTransactionsSchema,
  async (transactionIds) => {
    const user = await getUser();

    const event = await client.sendEvent({
      name: Events.TRANSACTIONS_EXPORT,
      payload: {
        transactionIds,
        teamId: user.data.team_id,
        locale: user.data.locale,
      },
    });

    const logsnag = await setupLogSnag({
      userId: user.data.id,
      fullName: user.data.full_name,
    });

    logsnag.track({
      event: LogEvents.ExportTransactions.name,
      icon: LogEvents.ExportTransactions.icon,
      channel: LogEvents.ExportTransactions.channel,
    });

    return event;
  }
);
```

<br />

We have a lot of events and charts pushing us to take right decisions, you can find the source code for this in our repository [here](https://git.new/midday).
